
#pragma once

namespace atr {

/**
 * @brief Namespace only for internal use of atr library
 * @details Please don't use this namespace outside the atr library. IF you REALLY need to - do it with special care.
 */
namespace __ {

template <class This, class Position, class Other, class ... Iterators>
    struct __splice;

template <template <class...> class Base, class ... Types,
          template <class, class> class Iterator, class ... Prevs,
                                                  class ... Nexts,
          template <class...> class NewBase,
          class ... Others>
struct __splice<Base<Types...>,
                Iterator<Base<Prevs...>, Base<Nexts...>>,
                NewBase<Others...>>
{
    static_assert(std::is_same<Base<Types...>,
                               Base<Prevs..., Nexts...>>::value,
                  "<Position> iterator have to belong to proper container");

    using type = Base<Prevs..., Others..., Nexts...>;
};

template <template <class...> class Base, class ... Types,
          template <class, class> class Iterator, class ... Prevs,
                                                  class ... Nexts,
          template <class...> class NewBase,
          class ... Others,
          class ... ElementPrevs, class Element, class ... ElementNexts>
struct __splice<Base<Types...>,
                Iterator<Base<Prevs...>, Base<Nexts...>>,
                NewBase<Others...>,
                Iterator<NewBase<ElementPrevs...>,
                                 NewBase<Element, ElementNexts...>>>
{
    static_assert(std::is_same<Base<Types...>,
                               Base<Prevs..., Nexts...>>::value,
                  "<Position> iterator have to belong to proper container");
    static_assert(std::is_same<NewBase<Others...>,
                               NewBase<ElementPrevs...,
                                       Element,
                                       ElementNexts...>>::value,
                  "<Element> have to be from container <Other>");

    using type = Base<Prevs..., Element, Nexts...>;
};

    ////////////////////
    // First Last

template <template <class...> class Base, class ... Types,
          template <class, class> class Iterator, class ... Prevs,
                                                  class ... Nexts,
          template <class...> class NewBase,
          class ... Others,
          class ... FirstNexts,
          class ... LastPrevs, class ... LastNexts>
struct __splice<Base<Types...>,
                Iterator<Base<Prevs...>, Base<Nexts...>>,
                NewBase<Others...>,
                Iterator<NewBase<>, NewBase<FirstNexts...>>,
                Iterator<NewBase<LastPrevs...>, NewBase<LastNexts...>>>
{
    static_assert(std::is_same<Base<Types...>,
                               Base<Prevs..., Nexts...>>::value,
                  "<Position> iterator have to belong to proper container");
    static_assert(std::is_same<NewBase<FirstNexts...>,
                               NewBase<LastPrevs..., LastNexts...>>::value,
                  "<First> have to be from same container than <Last>");

    using type = Base<Prevs..., LastPrevs..., Nexts...>;
};

template <template <class...> class Base, class ... Types,
          template <class, class> class Iterator, class ... Prevs,
                                                  class ... Nexts,
          template <class...> class NewBase,
          class ... Others,
          class First, class ... FirstPrevs, class ... FirstNexts,
          class Last, class ... LastPrevs, class ... LastNexts>
struct __splice<Base<Types...>,
                Iterator<Base<Prevs...>, Base<Nexts...>>,
                NewBase<Others...>,
                Iterator<NewBase<First, FirstPrevs...>, NewBase<FirstNexts...>>,
                Iterator<NewBase<Last, LastPrevs...>, NewBase<LastNexts...>>>
    : public __splice<Base<Types...>,
                      Iterator<Base<Prevs...>, Base<Nexts...>>,
                      NewBase<Others...>,
                      Iterator<NewBase<FirstPrevs...>, NewBase<FirstNexts...>>,
                      Iterator<NewBase<LastPrevs...>, NewBase<LastNexts...>>>
{
    static_assert(std::is_same<Base<Types...>,
                               Base<Prevs..., Nexts...>>::value,
                  "<Position> iterator have to belong to proper container");
    static_assert(std::is_same<NewBase<Others...>,
                               NewBase<First,
                                       FirstPrevs...,
                                       FirstNexts...>>::value,
                  "<First> have to be from container <Other>");
    static_assert(std::is_same<NewBase<Others...>,
                               NewBase<Last,
                                       LastPrevs...,
                                       LastNexts...>>::value,
                  "<Last> have to be from container <Other>");
    static_assert(std::is_same<NewBase<First, FirstPrevs..., FirstNexts...>,
                               NewBase<Last, LastPrevs..., LastNexts...>>::value,
                  "<First> have to be from same container than <Last>");
};

} // namespace __
} // namespace atr